/**
 * @file    app_airbag_system.c
 * @author  yhy
 * @brief   气袋通用接口源文件
 * @version 1.04
 * @date    2025-07-30
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-30     yhy          the first version V1.00
 * 2025-10-22     yhy          修复了system_callbacks被覆盖的问题 V1.01
 * 2025-10-27     yhy          新增气袋气压阈值保护监测 V1.02
 * 2025-11-03     yhy          - 修改了气泵控制逻辑，将气泵独立，设置气袋状态时不必修改气泵
 *                             - 新增阀门仲裁，根据气泵状态仲裁抽气状态 V1.03
 * 2025-11-12     yhy          修复与按摩的冲突，当按摩开启时，不启用电磁阀仲裁 V1.04
 *
 */
#include "app_airbag_system.h"

#include "app_massage.h"
#include "common_debug.h"
#include "inf_pump.h"

static void           app_airbag_system_stop_all_valves(airbag_system_t *system);
static void           app_airbag_system_update_airbag_timer(airbag_system_t *system);
static void           app_airbag_system_check_inflate_limits(airbag_system_t *system);
static result_e       app_airbag_system_validate_airbag_idx(const airbag_system_t *system, uint32_t idx);
static result_e       app_airbag_system_update_pressure(airbag_system_t *system);
static void           app_airbag_system_air_pressure_protect(airbag_system_t *system);
static airbag_state_e app_airbag_system_find_pump_state(void);
static void           app_airbag_system_arbitration_airbag_state(airbag_state_e airbag_state);

/* 气袋系统回调函数集合 */
static airbag_system_callbacks_t system_callbacks[AIRBAG_SYSTEM_TYPE_MAX];

/* 气袋系统列表 */
static airbag_system_t *airbag_systems[AIRBAG_SYSTEM_TYPE_MAX];

/**
 * @brief 初始化气袋系统
 *
 * @param system    气袋系统指针
 * @param config    气袋系统配置指针
 * @param type      气袋系统类型
 * @param callbacks 气袋系统回调函数指针
 * @return result_e 初始化结果, 成功返回RESULT_STATUS_OK, 失败返回其他错误码
 */
result_e app_airbag_system_init(airbag_system_t *system, const airbag_system_config_t *config,
                                airbag_system_type_e type, const airbag_system_callbacks_t *callbacks)
{
    if (!system || !config || !config->airbag_count) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 保存回调函数 */
    system_callbacks[type] = *callbacks;

    /* 初始化系统基本信息 */
    system->system_type            = type;
    system->system_state           = AIRBAG_SYSTEM_STATE_IDLE;
    system->mode                   = GENERAL_MODE_KEEP; /* 默认模式为保压模式 */
    system->airbag_count           = config->airbag_count;
    system->air_pressure_threshold = config->air_pressure_threshold;
    system->config                 = *config;

    /* 初始化传感器映射 */
    for (uint8_t i = 0; i < config->airbag_count; ++i) {
        system->sensor_mapping[i] = config->valve_configs[i].pressure_sensor_idx;
    }

    /* 初始化所有气袋 */
    for (uint8_t i = 0; i < config->airbag_count; ++i) {
        result_e result =
            inf_airbag_init(&system->airbags[i], config->valve_configs[i].inflate_valve_ch,
                            config->valve_configs[i].deflate_valve_ch, config->max_inflate_time_ms,
                            config->dispatching_cycle_ms, config->dispatching_cycle_ms);
        if (result != RESULT_STATUS_OK) {
            return result;
        }
    }

    system->initialized  = true;
    airbag_systems[type] = system; // 保存系统指针
    return RESULT_STATUS_OK;
}

/**
 * @brief 设置气袋系统运行模式
 *
 * @param system    气袋系统指针
 * @param mode      运行模式
 * @return result_e 设置结果, 成功返回RESULT_STATUS_OK, 失败返回其他错误码
 */
result_e app_airbag_system_set_mode(airbag_system_t *system, uint32_t mode)
{
    if (!system || !system->initialized) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 验证模式 */
    if (system_callbacks[system->system_type].validate_mode) {
        result_e result = system_callbacks[system->system_type].validate_mode(mode);
        if (result != RESULT_STATUS_OK) {
            return result;
        }
    }

    /* 检查是否为保压模式, 若是则关闭所有该系统的气袋 */
    if (mode == GENERAL_MODE_KEEP) {
        return app_airbag_system_stop(system);
    }

    /* 启动电磁阀系统 */
    result_e result = inf_solenoid_valve_set_system_enable(true);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    /* 应用新模式 */
    if (system_callbacks[system->system_type].apply_mode) {
        system_callbacks[system->system_type].apply_mode(system, mode);
    }

    system->mode         = mode;
    system->system_state = AIRBAG_SYSTEM_STATE_RUNNING;

    return RESULT_STATUS_OK;
}

/**
 * @brief 停止气袋系统
 *
 * @param   system      气袋系统指针
 * @return  result_e    停止结果, 成功返回RESULT_STATUS_OK, 失败返回其他错误码
 */
result_e app_airbag_system_stop(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 停止所有阀门, 关闭电磁阀系统 */
    app_airbag_system_stop_all_valves(system);
    inf_solenoid_valve_set_system_enable(false);

    /* 停止气泵 */
    inf_pump_air_stop();

    system->mode         = GENERAL_MODE_KEEP;
    system->system_state = AIRBAG_SYSTEM_STATE_IDLE;

    return RESULT_STATUS_OK;
}

/**
 * @brief 处理气袋系统运行状态, 在调度器中循环调度
 *
 * @param system 气袋系统指针
 */
void app_airbag_system_handle(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return;
    }

    app_airbag_system_update_pressure(system);

    if (system->system_state == AIRBAG_SYSTEM_STATE_IDLE) {
        return;
    }

    app_airbag_system_air_pressure_protect(system);
    app_airbag_system_update_airbag_timer(system);
    app_airbag_system_check_inflate_limits(system);
}

/**
 * @brief 获取当前运行模式
 *
 * @param   system      气袋系统指针
 * @return  uint32_t    当前运行模式
 */
uint32_t app_airbag_system_get_mode(const airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return GENERAL_MODE_KEEP;
    }

    return system->mode;
}

/**
 * @brief 获取指定气袋(支撑)状态
 *
 * @param   system          气袋系统指针
 * @param   airbag_idx      气袋索引
 * @return  airbag_state_e  气袋支撑状态
 */
airbag_state_e app_airbag_system_get_airbag_state(const airbag_system_t *system, uint32_t airbag_idx)
{
    if (!system || !system->initialized ||
        app_airbag_system_validate_airbag_idx(system, airbag_idx) != RESULT_STATUS_OK) {
        return AIRBAG_STATE_UNKNOWN;
    }

    /* 特殊化处理, 抽气状态返回泄气, 这是为了更好的与信号兼容 */
    airbag_state_e airbag_state = inf_airbag_get_state(&system->airbags[airbag_idx]);
    if (airbag_state == AIRBAG_STATE_EXHAUST) {
        return AIRBAG_STATE_DEFLATE;
    }

    return airbag_state;
}

/**
 * @brief 获取指定气袋压力值
 *
 * @param system        气袋系统指针
 * @param airbag_idx    气袋索引
 * @return uint32_t     气袋压力值, 单位为KPa
 */
uint32_t app_airbag_system_get_air_pressure(const airbag_system_t *system, uint32_t airbag_idx)
{
    if (!system || !system->initialized ||
        app_airbag_system_validate_airbag_idx(system, airbag_idx) != RESULT_STATUS_OK) {
        return 0;
    }

    return (uint32_t)inf_airbag_get_air_pressure(&system->airbags[airbag_idx]);
}

/**
 * @brief 控制指定气袋(支撑)状态
 *
 * @param system        气袋系统指针
 * @param airbag_idx    气袋索引
 * @param state         气袋支撑状态
 */
void app_airbag_system_ctrl_airbag(airbag_system_t *system, uint32_t airbag_idx, airbag_state_e state)
{
    if (!system || !system->initialized ||
        app_airbag_system_validate_airbag_idx(system, airbag_idx) != RESULT_STATUS_OK) {
        return;
    }

    airbag_t *airbag = &system->airbags[airbag_idx];

    switch (state) {
    case AIRBAG_STATE_INFLATE:
        if (airbag->inflate_blocked) {
            LOG("%s airbag %d inflate blocked",
                system->system_type == AIRBAG_SYSTEM_TYPE_HIP     ? "hip"
                : system->system_type == AIRBAG_SYSTEM_TYPE_THIGH ? "thigh"
                                                                  : "flank",
                airbag_idx);
            return;
        }
        inf_airbag_set_state(airbag, AIRBAG_STATE_INFLATE);
        break;
    case AIRBAG_STATE_DEFLATE: inf_airbag_set_state(airbag, AIRBAG_STATE_DEFLATE); break;
    case AIRBAG_STATE_KEEP:    inf_airbag_set_state(airbag, AIRBAG_STATE_KEEP); break;
    case AIRBAG_STATE_EXHAUST: inf_airbag_set_state(airbag, AIRBAG_STATE_EXHAUST); break;
    }
}

/**
 * @brief 阀门仲裁, 用于协调多个气袋系统的阀门操作
 *
 */
void app_airbag_system_pump_valve_coordination(void)
{
    /* 当按摩开启时，不气动阀门和气泵仲裁 */
    if (app_massage_get_switch() == MASSAGE_SWITCH_STATE_ON) {
        return;
    }

    /* 查找当前需要的气泵操作状态 */
    airbag_state_e airbag_state = app_airbag_system_find_pump_state();

    /* 根据需要的状态控制气泵 */
    switch (airbag_state) {
    case AIRBAG_STATE_INFLATE: inf_pump_air_inflation(); break;
    case AIRBAG_STATE_EXHAUST: inf_pump_air_exhaust(); break;
    default:                   inf_pump_air_stop(); break;
    }

    /* 在充气状态下，任意一个抽气状态，都要修改为自然泄气 */
    app_airbag_system_arbitration_airbag_state(airbag_state);
}

/**
 * @brief 仲裁气袋状态
 *
 * @param airbag_state 当前需要的气泵操作状态
 */
static void app_airbag_system_arbitration_airbag_state(airbag_state_e airbag_state)
{
    /* 只有充气状态需要仲裁 */
    if (airbag_state != AIRBAG_STATE_INFLATE) {
        return;
    }

    /* 遍历所有气袋系统 */
    for (uint8_t i = 0; i < AIRBAG_SYSTEM_TYPE_MAX; ++i) {
        const airbag_system_t *system = airbag_systems[i];
        if (!system || !system->initialized || system->system_type == AIRBAG_SYSTEM_TYPE_ALL) {
            continue;
        }

        /* 遍历对应的气袋，检查状态 */
        for (uint8_t j = 0; j < system->airbag_count; ++j) {
            airbag_t *airbag = &system->airbags[j];
            /* 如果气袋状态为抽气，修改为自然泄气 */
            if (airbag->state == AIRBAG_STATE_EXHAUST) {
                inf_airbag_set_state(airbag, AIRBAG_STATE_DEFLATE);
            }
        }
    }
}

/**
 * @brief 查找需要气泵操作的气袋状态
 *
 * @return airbag_state_e 返回需要的气泵操作状态，优先级：充气 > 抽气 > 保压
 */
static airbag_state_e app_airbag_system_find_pump_state(void)
{
    bool has_exhaust = false;

    /* 遍历所有气袋系统 */
    for (uint8_t i = 0; i < AIRBAG_SYSTEM_TYPE_MAX; ++i) {
        const airbag_system_t *system = airbag_systems[i];
        if (!system || !system->initialized || system->system_type == AIRBAG_SYSTEM_TYPE_ALL) {
            continue;
        }

        /* 遍历对应的气袋，检查状态 */
        for (uint8_t j = 0; j < system->airbag_count; ++j) {
            const airbag_t *airbag = &system->airbags[j];

            /* 充气状态优先级最高，立即返回 */
            if (airbag->state == AIRBAG_STATE_INFLATE) {
                return AIRBAG_STATE_INFLATE;
            }

            /* 记录是否有抽气需求 */
            if (airbag->state == AIRBAG_STATE_EXHAUST) {
                has_exhaust = true;
            }
        }
    }

    /* 返回抽气状态或保压状态 */
    return has_exhaust ? AIRBAG_STATE_EXHAUST : AIRBAG_STATE_KEEP;
}

/**
 * @brief 气压保护监测，当气压值高于阈值时，触发保护机制
 *
 * @param system 气袋系统指针
 */
static void app_airbag_system_air_pressure_protect(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return;
    }

    /* 遍历系统中的所有气袋 */
    for (uint8_t i = 0; i < system->airbag_count; ++i) {
        airbag_t *airbag           = &system->airbags[i];
        uint32_t  current_pressure = airbag->air_pressure;

        /* 检查气压是否超过阈值且气袋处于充气状态 */
        if (current_pressure > system->air_pressure_threshold && airbag->state == AIRBAG_STATE_INFLATE) {
            /* 停止充气，设置为保压状态 */
            app_airbag_system_ctrl_airbag(system, i, AIRBAG_STATE_KEEP);

            /* 设置充气阻塞标志位 */
            airbag->inflate_blocked = true;

            LOG("%s airbag %u air pressure %u kPa exceeds threshold %u kPa, inflate blocked",
                system->system_type == AIRBAG_SYSTEM_TYPE_HIP      ? "hip"
                : system->system_type == AIRBAG_SYSTEM_TYPE_THIGH  ? "thigh"
                : system->system_type == AIRBAG_SYSTEM_TYPE_LUMBAR ? "lumbar"
                                                                   : "flank",
                i, current_pressure, system->air_pressure_threshold);
        }
        /* 检查是否可以解除充气阻塞 */
        else if (current_pressure <= system->air_pressure_threshold &&
                 airbag->inflate_time_ms < airbag->max_inflate_time_ms && airbag->inflate_blocked) {
            /* 解除充气阻塞标志位 */
            airbag->inflate_blocked = false;

            /* 记录日志 */
            LOG("%s airbag %u air pressure %u kPa below threshold %u kPa, inflate unblocked",
                system->system_type == AIRBAG_SYSTEM_TYPE_HIP      ? "hip"
                : system->system_type == AIRBAG_SYSTEM_TYPE_THIGH  ? "thigh"
                : system->system_type == AIRBAG_SYSTEM_TYPE_LUMBAR ? "lumbar"
                                                                   : "flank",
                i, current_pressure, system->air_pressure_threshold);
        }
    }
}

/**
 * @brief 更新气袋系统中所有气袋的压力值
 *
 * @param system        气袋系统指针
 * @return result_e     更新结果, 成功返回RESULT_STATUS_OK, 失败返回其他错误码
 */
static result_e app_airbag_system_update_pressure(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    /* 更新每个气袋的压力值 */
    for (uint8_t i = 0; i < system->airbag_count; ++i) {
        cps121_idx_e sensor_idx = system->sensor_mapping[i];
        if (sensor_idx < CPS121_IDX_MAX) {
            system->airbags[i].air_pressure = cps121_sensor_list[sensor_idx].air_pressure;
        }
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief 停止所有气袋(支撑)阀门
 *
 * @param system    气袋系统指针
 */
static void app_airbag_system_stop_all_valves(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return;
    }

    for (uint8_t i = 0; i < system->airbag_count; ++i) {
        app_airbag_system_ctrl_airbag(system, i, AIRBAG_STATE_KEEP);
    }
}

/**
 * @brief 更新气袋计数器
 *
 * @param system    气袋系统指针
 */
static void app_airbag_system_update_airbag_timer(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return;
    }

    for (uint8_t i = 0; i < system->airbag_count; ++i) {
        airbag_t *airbag = &system->airbags[i];

        if (airbag->state == AIRBAG_STATE_INFLATE) {
            airbag->inflate_time_ms += airbag->inflate_rate_ms;
        }
        else if (airbag->state == AIRBAG_STATE_DEFLATE || airbag->state == AIRBAG_STATE_EXHAUST) {

            /* 泄气状态：减少充气时间 */
            if (airbag->inflate_time_ms >= airbag->deflate_rate_ms) {
                airbag->inflate_time_ms -= airbag->deflate_rate_ms;
            }
            else {
                airbag->inflate_time_ms = 0U;
            }

            /* 如果没有达到充到最大时间且气压安全，解除充气阻止状态 */
            if (airbag->inflate_time_ms < airbag->max_inflate_time_ms &&
                airbag->air_pressure <= system->air_pressure_threshold) {
                airbag->inflate_blocked = false;
            }
        }
    }
}

/**
 * @brief 检查气袋充气时间限制
 *
 * @param system  气袋系统指针
 */
static void app_airbag_system_check_inflate_limits(airbag_system_t *system)
{
    if (!system || !system->initialized) {
        return;
    }

    for (uint8_t i = 0; i < system->airbag_count; ++i) {
        airbag_t *airbag = &system->airbags[i];

        if (airbag->state == AIRBAG_STATE_INFLATE &&
            airbag->inflate_time_ms >= airbag->max_inflate_time_ms) {

            /* 停止充气, 阻止继续充气 */
            app_airbag_system_ctrl_airbag(system, i, AIRBAG_STATE_KEEP);
            airbag->inflate_blocked = true;

            /* 检查是否所有气袋都停止充气或抽气，如果是则停止气泵 */
            bool any_inflating = false;
            for (uint8_t j = 0; j < system->airbag_count; j++) {
                if (system->airbags[j].state == AIRBAG_STATE_INFLATE ||
                    system->airbags[j].state == AIRBAG_STATE_EXHAUST) {

                    any_inflating = true;
                    break;
                }
            }
            if (!any_inflating) {
                inf_pump_air_stop();
            }

            LOG("%s airbag %u inflate time limit reached, inflate blocked\n",
                system->system_type == AIRBAG_SYSTEM_TYPE_HIP     ? "hip"
                : system->system_type == AIRBAG_SYSTEM_TYPE_THIGH ? "thigh"
                                                                  : "flank",
                i);
        }
    }
}

/**
 * @brief 验证气袋索引是否有效
 *
 * @param system        气袋系统指针
 * @param airbag_idx    气袋索引
 * @return result_e     验证结果
 */
static result_e app_airbag_system_validate_airbag_idx(const airbag_system_t *system, uint32_t airbag_idx)
{
    if (!system || !system->initialized) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (airbag_idx >= system->airbag_count) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    return RESULT_STATUS_OK;
}
